package online.heycm.platform.redis;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import online.heycm.platform.common.entity.exception.Assert;
import online.heycm.platform.common.tools.Jackson;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * @author heycm
 * @since 2023/11/11 16:19
 */
public class RedisCacheImpl implements RedisCache {

    private final RedisTemplate<String, Object> redisTemplate;

    private static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS;

    private final String namespace;

    public RedisCacheImpl(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
        this.namespace = "";
    }

    public RedisCacheImpl(RedisTemplate<String, Object> redisTemplate, String namespace) {
        this.redisTemplate = redisTemplate;
        this.namespace = namespace;
    }

    private boolean redisOperator(RedisOperator redisOperator) {
        try {
            return redisOperator.operate();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private boolean redisOperatorVoid(RedisOperatorVoid redisOperatorVoid) {
        try {
            redisOperatorVoid.operate();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private long redisOperatorNumber(RedisOperatorNumber redisOperatorNumber) {
        try {
            return redisOperatorNumber.operate();
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    private <T> T redisOperatorT(RedisOperatorT<T> redisOperatorT) {
        try {
            return redisOperatorT.operate();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public boolean del(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperator(() -> redisTemplate.delete(finalKey));
    }

    @Override
    public boolean delNamespace(String namespace, String key) {
        return del(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public long del(String... keys) {
        String[] finalKeys = RedisCacheUtil.namespace(namespace, keys);
        return redisOperatorNumber(() -> redisTemplate.delete(Arrays.asList(finalKeys)));
    }

    @Override
    public long delNamespace(String namespace, String... keys) {
        return del(RedisCacheUtil.namespace(namespace, keys));
    }

    @Override
    public boolean expire(String key, long millisecond) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperator(() -> redisTemplate.expire(finalKey, millisecond, TIME_UNIT));
    }

    @Override
    public boolean expireNamespace(String namespace, String key, long millisecond) {
        return expire(RedisCacheUtil.namespace(namespace, key), millisecond);
    }

    @Override
    public long getExpire(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.getExpire(finalKey));
    }

    @Override
    public long getExpireNamespace(String namespace, String key) {
        return getExpire(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public boolean hasKey(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperator(() -> redisTemplate.hasKey(finalKey));
    }

    @Override
    public boolean hasKeyNamespace(String namespace, String key) {
        return hasKey(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public boolean set(String key, String value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorVoid(() -> redisTemplate.boundValueOps(finalKey).set(value));
    }

    @Override
    public boolean setNamespace(String namespace, String key, String value) {
        return set(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public boolean set(String key, String value, long millisecond) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorVoid(() -> redisTemplate.boundValueOps(finalKey).set(value, millisecond, TIME_UNIT));
    }

    @Override
    public boolean setNamespace(String namespace, String key, String value, long millisecond) {
        return set(RedisCacheUtil.namespace(namespace, key), value, millisecond);
    }

    @Override
    public boolean setNx(String key, String value, long millisecond) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorVoid(() -> redisTemplate.boundValueOps(finalKey).setIfAbsent(value, millisecond, TIME_UNIT));
    }

    @Override
    public boolean setNx(String namespace, String key, String value, long millisecond) {
        return setNx(RedisCacheUtil.namespace(namespace, key), value, millisecond);
    }


    @Override
    public String get(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> (String) redisTemplate.boundValueOps(finalKey).get());
    }

    @Override
    public String getNamespace(String namespace, String key) {
        return get(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public long incr(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return incr(finalKey, 1);
    }

    @Override
    public long incrNamespace(String namespace, String key) {
        return incr(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public long incr(String key, long delta) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundValueOps(finalKey).increment(Math.abs(delta)));
    }

    @Override
    public long incrNamespace(String namespace, String key, long delta) {
        return incr(RedisCacheUtil.namespace(namespace, key), delta);
    }

    @Override
    public long decr(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return decr(finalKey, 1);
    }

    @Override
    public long decrNamespace(String namespace, String key) {
        return decr(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public long decr(String key, long delta) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundValueOps(finalKey).increment(-Math.abs(delta)));
    }

    @Override
    public long decrNamespace(String namespace, String key, long delta) {
        return decr(RedisCacheUtil.namespace(namespace, key), delta);
    }

    @Override
    public <T> boolean hSetObject(String key, T value) {
        Map<String, Object> data;
        if (value instanceof Map) {
            data = (Map<String, Object>) value;
        } else {
            data = Jackson.toObject(Jackson.toJson(value), Map.class);
        }
        Assert.notNull(data, "RedisCache hSetObject invalid value: " + value);
        return hSet(key, data);
    }

    @Override
    public <T> boolean hSetNamespaceObject(String namespace, String key, T value) {
        Map<String, Object> data;
        if (value instanceof Map) {
            data = (Map<String, Object>) value;
        } else {
            data = Jackson.toObject(Jackson.toJson(value), Map.class);
        }
        Assert.notNull(data, "RedisCache hSetObject invalid value: " + value);
        return hSetNamespace(namespace, key, data);
    }

    @Override
    public <T> boolean hSetObject(String key, T value, long millisecond) {
        Map<String, Object> data;
        if (value instanceof Map) {
            data = (Map<String, Object>) value;
        } else {
            data = Jackson.toObject(Jackson.toJson(value), Map.class);
        }
        Assert.notNull(data, "RedisCache hSetObject invalid value: " + value);
        return hSet(key, data, millisecond);
    }

    @Override
    public <T> boolean hSetNamespaceObject(String namespace, String key, T value, long millisecond) {
        Map<String, Object> data;
        if (value instanceof Map) {
            data = (Map<String, Object>) value;
        } else {
            data = Jackson.toObject(Jackson.toJson(value), Map.class);
        }
        Assert.notNull(data, "RedisCache hSetNamespaceObject invalid value: " + value);
        return hSetNamespace(namespace, key, data, millisecond);
    }

    @Override
    public boolean hSet(String key, Map<String, Object> value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorVoid(() -> redisTemplate.boundHashOps(finalKey).putAll(value));
    }

    @Override
    public boolean hSetNamespace(String namespace, String key, Map<String, Object> value) {
        return hSet(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public boolean hSet(String key, Map<String, Object> value, long millisecond) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorVoid(() -> {
            BoundHashOperations<String, Object, Object> boundHashOps = redisTemplate.boundHashOps(finalKey);
            boundHashOps.putAll(value);
            boundHashOps.expire(millisecond, TIME_UNIT);
        });
    }

    @Override
    public boolean hSetNamespace(String namespace, String key, Map<String, Object> value, long millisecond) {
        return hSet(RedisCacheUtil.namespace(namespace, key), value, millisecond);
    }

    @Override
    public boolean hSet(String key, String item, Object value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorVoid(() -> redisTemplate.boundHashOps(finalKey).put(item, value));
    }

    @Override
    public boolean hSetNamespace(String namespace, String key, String item, Object value) {
        return hSet(RedisCacheUtil.namespace(namespace, key), item, value);
    }

    @Override
    public boolean hSet(String key, String item, Object value, long millisecond) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorVoid(() -> {
            BoundHashOperations<String, Object, Object> boundHashOps = redisTemplate.boundHashOps(finalKey);
            boundHashOps.put(item, value);
            boundHashOps.expire(millisecond, TIME_UNIT);
        });
    }

    @Override
    public boolean hSetNamespace(String namespace, String key, String item, Object value, long millisecond) {
        return hSet(RedisCacheUtil.namespace(namespace, key), item, value, millisecond);
    }

    @Override
    public Map<String, Object> hGet(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(
                () -> Jackson.toObject(Jackson.toJson(redisTemplate.boundHashOps(finalKey).entries()), Map.class));
    }

    @Override
    public Map<String, Object> hGetNamespace(String namespace, String key) {
        return hGet(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public <T> T hGet(String key, Class<T> clazz) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> {
            Map<Object, Object> entries = redisTemplate.boundHashOps(finalKey).entries();
            if (entries == null) {
                return null;
            }
            return Jackson.toObject(Jackson.toJson(entries), clazz);
        });
    }

    @Override
    public <T> T hGetNamespace(String namespace, String key, Class<T> clazz) {
        return hGet(RedisCacheUtil.namespace(namespace, key), clazz);
    }

    @Override
    public Object hGet(String key, String item) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundHashOps(finalKey).get(item));
    }

    @Override
    public Object hGetNamespace(String namespace, String key, String item) {
        return hGet(RedisCacheUtil.namespace(namespace, key), item);
    }

    @Override
    public long hDel(String key, String item) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundHashOps(finalKey).delete(item));
    }

    @Override
    public long hDelNamespace(String namespace, String key, String item) {
        return hDel(RedisCacheUtil.namespace(namespace, key), item);
    }

    @Override
    public long hDel(String key, String... items) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundHashOps(finalKey).delete(items));
    }

    @Override
    public long hDelNamespace(String namespace, String key, String... items) {
        return hDel(RedisCacheUtil.namespace(namespace, key), items);
    }

    @Override
    public long hIncr(String key, String item) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return hIncr(finalKey, item, 1);
    }

    @Override
    public long hIncrNamespace(String namespace, String key, String item) {
        return hIncr(RedisCacheUtil.namespace(namespace, key), item);
    }

    @Override
    public long hIncr(String key, String item, long delta) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundHashOps(finalKey).increment(item, Math.abs(delta)));
    }

    @Override
    public long hIncrNamespace(String namespace, String key, String item, long delta) {
        return hIncr(RedisCacheUtil.namespace(namespace, key), item, delta);
    }

    @Override
    public long hDecr(String key, String item) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return hDecr(finalKey, item, 1);
    }

    @Override
    public long hDecrNamespace(String namespace, String key, String item) {
        return hDecr(RedisCacheUtil.namespace(namespace, key), item);
    }

    @Override
    public long hDecr(String key, String item, long delta) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundHashOps(finalKey).increment(item, -Math.abs(delta)));
    }

    @Override
    public long hDecrNamespace(String namespace, String key, String item, long delta) {
        return hDecr(RedisCacheUtil.namespace(namespace, key), item, delta);
    }

    @Override
    public boolean hHasItem(String key, String item) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperator(() -> redisTemplate.boundHashOps(finalKey).hasKey(item));
    }

    @Override
    public boolean hHasItemNamespace(String namespace, String key, String item) {
        return hHasItem(RedisCacheUtil.namespace(namespace, key), item);
    }

    @Override
    public Set<String> hItems(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(
                () -> Jackson.toCollection(Jackson.toJson(redisTemplate.boundHashOps(finalKey).keys()), Set.class,
                        String.class));
    }

    @Override
    public Set<String> hItemsNamespace(String namespace, String key) {
        return hItems(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public List<Object> hValues(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundHashOps(finalKey).values());
    }

    @Override
    public List<Object> hValuesNamespace(String namespace, String key) {
        return hValues(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public long sSet(String key, Object... values) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundSetOps(finalKey).add(values));
    }

    @Override
    public long sSetNamespace(String namespace, String key, Object... values) {
        return sSet(RedisCacheUtil.namespace(namespace, key), values);
    }

    @Override
    public long sSet(String key, long millisecond, Object... values) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> {
            BoundSetOperations<String, Object> boundSetOps = redisTemplate.boundSetOps(finalKey);
            boundSetOps.expire(millisecond, TIME_UNIT);
            return boundSetOps.add(values);
        });
    }

    @Override
    public long sSetNamespace(String namespace, String key, long millisecond, Object... values) {
        return sSet(RedisCacheUtil.namespace(namespace, key), millisecond, values);
    }

    @Override
    public long sSet(String key, Set<Object> value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundSetOps(finalKey).add(value));
    }

    @Override
    public long sSetNamespace(String namespace, String key, Set<Object> value) {
        return sSet(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public long sSet(String key, Set<Object> value, long millisecond) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> {
            BoundSetOperations<String, Object> boundSetOps = redisTemplate.boundSetOps(finalKey);
            boundSetOps.expire(millisecond, TIME_UNIT);
            return boundSetOps.add(value);
        });
    }

    @Override
    public long sSetNamespace(String namespace, String key, Set<Object> value, long millisecond) {
        return sSet(RedisCacheUtil.namespace(namespace, key), value, millisecond);
    }

    @Override
    public Set<Object> sGet(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundSetOps(finalKey).members());
    }

    @Override
    public Set<Object> sGetNamespace(String namespace, String key) {
        return sGet(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public boolean sHasValue(String key, Object value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperator(() -> redisTemplate.boundSetOps(finalKey).isMember(value));
    }

    @Override
    public boolean sHasValueNamespace(String namespace, String key, Object value) {
        return sHasValue(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public long sDel(String key, Object value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundSetOps(finalKey).remove(value));
    }

    @Override
    public long sDelNamespace(String namespace, String key, Object value) {
        return sDel(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public long sDel(String key, Object... values) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundSetOps(finalKey).remove(values));
    }

    @Override
    public long sDelNamespace(String namespace, String key, Object... values) {
        return sDel(RedisCacheUtil.namespace(namespace, key), values);
    }

    @Override
    public long sSize(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundSetOps(finalKey).size());
    }

    @Override
    public long sSizeNamespace(String namespace, String key) {
        return sSize(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public long lRightPush(String key, Object... values) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundListOps(finalKey).rightPushAll(values));
    }

    @Override
    public long lRightPushNamespace(String namespace, String key, Object... values) {
        return lRightPush(RedisCacheUtil.namespace(namespace, key), values);
    }

    @Override
    public long lRightPush(String key, long millisecond, Object... values) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> {
            BoundListOperations<String, Object> boundListOps = redisTemplate.boundListOps(finalKey);
            boundListOps.expire(millisecond, TIME_UNIT);
            return boundListOps.rightPushAll(values);
        });
    }

    @Override
    public long lRightPushNamespace(String namespace, String key, long millisecond, Object... values) {
        return lRightPush(RedisCacheUtil.namespace(namespace, key), millisecond, values);
    }

    @Override
    public long lRightPush(String key, List<Object> value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundListOps(finalKey).rightPushAll(value));
    }

    @Override
    public long lRightPushNamespace(String namespace, String key, List<Object> value) {
        return lRightPush(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public long lRightPush(String key, long millisecond, List<Object> value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> {
            BoundListOperations<String, Object> boundListOps = redisTemplate.boundListOps(finalKey);
            boundListOps.expire(millisecond, TIME_UNIT);
            return boundListOps.rightPushAll(value);
        });
    }

    @Override
    public long lRightPushNamespace(String namespace, String key, long millisecond, List<Object> value) {
        return lRightPush(RedisCacheUtil.namespace(namespace, key), millisecond, value);
    }

    @Override
    public long lLeftPush(String key, Object... values) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundListOps(finalKey).leftPushAll(values));
    }

    @Override
    public long lLeftPushNamespace(String namespace, String key, Object... values) {
        return lLeftPush(RedisCacheUtil.namespace(namespace, key), values);
    }

    @Override
    public long lLeftPush(String key, long millisecond, Object... values) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> {
            BoundListOperations<String, Object> boundListOps = redisTemplate.boundListOps(key);
            boundListOps.expire(millisecond, TIME_UNIT);
            return boundListOps.leftPushAll(values);
        });
    }

    @Override
    public long lLeftPushNamespace(String namespace, String key, long millisecond, Object... values) {
        return lLeftPush(RedisCacheUtil.namespace(namespace, key), millisecond, values);
    }

    @Override
    public long lLeftPush(String key, List<Object> value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundListOps(finalKey).leftPushAll(value));
    }

    @Override
    public long lLeftPushNamespace(String namespace, String key, List<Object> value) {
        return lLeftPush(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public long lLeftPush(String key, long millisecond, List<Object> value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> {
            BoundListOperations<String, Object> boundListOps = redisTemplate.boundListOps(finalKey);
            boundListOps.expire(millisecond, TIME_UNIT);
            return boundListOps.leftPushAll(value);
        });
    }

    @Override
    public long lLeftPushNamespace(String namespace, String key, long millisecond, List<Object> value) {
        return lLeftPush(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public List<Object> lGet(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> {
            BoundListOperations<String, Object> boundListOps = redisTemplate.boundListOps(finalKey);
            if (boundListOps.size() <= 0) {
                return Collections.emptyList();
            }
            return boundListOps.range(0, boundListOps.size() - 1);
        });
    }

    @Override
    public List<Object> lGetNamespace(String namespace, String key) {
        return lGet(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public List<Object> lRange(String key, long start, long end) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> {
            BoundListOperations<String, Object> boundListOps = redisTemplate.boundListOps(finalKey);
            if (boundListOps.size() <= 0 || start >= boundListOps.size()) {
                return Collections.emptyList();
            }
            return boundListOps.range(start, Math.min(end, (boundListOps.size() - 1)));
        });
    }

    @Override
    public List<Object> lRangeNamespace(String namespace, String key, long start, long end) {
        return lRange(RedisCacheUtil.namespace(namespace, key), start, end);
    }

    @Override
    public Object lIndex(String key, long index) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> {
            BoundListOperations<String, Object> boundListOps = redisTemplate.boundListOps(finalKey);
            if (boundListOps.size() <= 0 || index >= boundListOps.size() || index < 0) {
                return null;
            }
            return boundListOps.index(index);
        });
    }

    @Override
    public Object lIndexNamespace(String namespace, String key, long index) {
        return lIndex(RedisCacheUtil.namespace(namespace, key), index);
    }

    @Override
    public Object lLeftPop(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundListOps(finalKey).leftPop());
    }

    @Override
    public Object lLeftPopNamespace(String namespace, String key) {
        return lLeftPop(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public Object lRightPop(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundListOps(finalKey).rightPop());
    }

    @Override
    public Object lRightPopNamespace(String namespace, String key) {
        return lRightPop(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public long lSize(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundListOps(finalKey).size());
    }

    @Override
    public long lSizeNamespace(String namespace, String key) {
        return lSize(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public boolean lSet(String key, long index, Object value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorVoid(() -> redisTemplate.boundListOps(finalKey).set(index, value));
    }

    @Override
    public boolean lSetNamespace(String namespace, String key, long index, Object value) {
        return lSet(RedisCacheUtil.namespace(namespace, key), index, value);
    }

    @Override
    public long lDel(String key, Object value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> {
            BoundListOperations<String, Object> boundListOps = redisTemplate.boundListOps(finalKey);
            return boundListOps.remove(boundListOps.size(), value);
        });
    }

    @Override
    public long lDelNamespace(String namespace, String key, Object value) {
        return lDel(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public long lDel(String key, long number, Object value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundListOps(finalKey).remove(number, value));
    }

    @Override
    public long lDelNamespace(String namespace, String key, long number, Object value) {
        return lDel(RedisCacheUtil.namespace(namespace, key), number, value);
    }

    @Override
    public boolean zSet(String key, Object value, long score) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperator(() -> redisTemplate.boundZSetOps(finalKey).add(value, score));
    }

    @Override
    public boolean zSetNamespace(String namespace, String key, Object value, long score) {
        return zSet(RedisCacheUtil.namespace(namespace, key), value, score);
    }

    @Override
    public Set<Object> zGet(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundZSetOps(finalKey).range(0, -1));
    }

    @Override
    public Set<Object> zGetNamespace(String namespace, String key) {
        return zGet(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public Set<Object> zRange(String key, long start, long end) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> {
            BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(finalKey);
            if (boundZSetOps.size() <= 0 || start >= boundZSetOps.size()) {
                return Collections.emptySet();
            }
            return boundZSetOps.range(start, Math.min(end, (boundZSetOps.size() - 1)));
        });
    }

    @Override
    public Set<Object> zRangeNamespace(String namespace, String key, long start, long end) {
        return zRange(RedisCacheUtil.namespace(namespace, key), start, end);
    }

    @Override
    public long zScore(String key, Object value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundZSetOps(finalKey).score(value).longValue());
    }

    @Override
    public long zScoreNamespace(String namespace, String key, Object value) {
        return zScore(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public long zSize(String key) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundZSetOps(finalKey).size());
    }

    @Override
    public long zSizeNamespace(String namespace, String key) {
        return zSize(RedisCacheUtil.namespace(namespace, key));
    }

    @Override
    public long zCount(String key, long minScore, long maxScore) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundZSetOps(finalKey).count(minScore, maxScore));
    }

    @Override
    public long zCountNamespace(String namespace, String key, long minScore, long maxScore) {
        return zCount(RedisCacheUtil.namespace(namespace, key), minScore, maxScore);
    }

    @Override
    public Set<Object> zRangeByScore(String key, long minScore, long maxScore) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundZSetOps(finalKey).rangeByScore(minScore, maxScore));
    }

    @Override
    public Set<Object> zRangeByScoreNamespace(String namespace, String key, long minScore, long maxScore) {
        return zRangeByScore(RedisCacheUtil.namespace(namespace, key), minScore, maxScore);
    }

    @Override
    public Set<Object> zReverseRangeByScore(String key, long minScore, long maxScore) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundZSetOps(finalKey).reverseRangeByScore(minScore, maxScore));
    }

    @Override
    public Set<Object> zReverseRangeByScoreNamespace(String namespace, String key, long minScore, long maxScore) {
        return zReverseRangeByScore(RedisCacheUtil.namespace(namespace, key), minScore, maxScore);
    }

    @Override
    public long zRank(String key, Object value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundZSetOps(finalKey).rank(value));
    }

    @Override
    public long zRankNamespace(String namespace, String key, Object value) {
        return zRank(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public long zReverseRank(String key, Object value) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundZSetOps(finalKey).reverseRank(value));
    }

    @Override
    public long zReverseRankNamespace(String namespace, String key, Object value) {
        return zReverseRank(RedisCacheUtil.namespace(namespace, key), value);
    }

    @Override
    public long zDel(String key, Object... values) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundZSetOps(finalKey).remove(values));
    }

    @Override
    public long zDelNamespace(String namespace, String key, Object... values) {
        return zDel(RedisCacheUtil.namespace(namespace, key), values);
    }

    @Override
    public long zDelRange(String key, long start, long end) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> {
            BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(finalKey);
            if (start >= boundZSetOps.size() || end <= 0) {
                return 0;
            }
            return boundZSetOps.removeRange(start, Math.min(end, (boundZSetOps.size() - 1)));
        });
    }

    @Override
    public long zDelRangeNamespace(String namespace, String key, long start, long end) {
        return zDelRange(RedisCacheUtil.namespace(namespace, key), start, end);
    }

    @Override
    public long zDelScore(String key, long minScore, long maxScore) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorNumber(() -> redisTemplate.boundZSetOps(finalKey).removeRangeByScore(minScore, maxScore));
    }

    @Override
    public long zDelScoreNamespace(String namespace, String key, long minScore, long maxScore) {
        return zDelScore(RedisCacheUtil.namespace(namespace, key), minScore, maxScore);
    }

    @Override
    public long zIncrScore(String key, Object value, long score) {
        String finalKey = RedisCacheUtil.namespace(namespace, key);
        return redisOperatorT(() -> redisTemplate.boundZSetOps(finalKey).incrementScore(value, score).longValue());
    }

    @Override
    public long zIncrScoreNamespace(String namespace, String key, Object value, long score) {
        return zIncrScore(RedisCacheUtil.namespace(namespace, key), value, score);
    }
}
